/* __auth__ : KunLin */
package com.cskaoyan.utils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

public class CopyModuleClassUtils {
    /**
     * @param source 数据源
     * @param targetClass 替换后的数据源
     * @param parameterMap key为BO类特有的属性, val为Bean类特有的属性，且BO特有属性对应的值为Bean特有属性对应的值
     * @param <T> Bean类
     * @return 通过BO类替换成Bean类
     */
    private static <T, E> T copy(E source, Class<T> targetClass, Map<String, String> parameterMap) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        // 实例化类targetClass
        T t = targetClass.getConstructor().newInstance();

        // 获取source类里面的字段
        Field[] sourceFields = source.getClass().getDeclaredFields();

        Field targetField;
        // 循环source类里面的字段
        for (Field sourceField : sourceFields) {
            // 拿到source字段的名字
            String sourceName = sourceField.getName();
            sourceField.setAccessible(true);
            // 如果Map存在就执行
            if (hasParameters(source, parameterMap, t, sourceField, sourceName)) continue;
            try { // 如果source里面有的字段，而targetClass没有，那就什么都不需要做即可
                targetField = t.getClass().getDeclaredField(sourceName);
            }catch (NoSuchFieldException | SecurityException e){
                continue; // 什么也不错
            }
            targetField.setAccessible(true);
            targetField.set(t,sourceField.get(source));
        }
        return t;
    }


    private static <T, E> boolean hasParameters(E source, Map<String, String> parameterMap, T target, Field sourceField, String sourceName) throws NoSuchFieldException, IllegalAccessException {
        if (parameterMap == null){
            return false;
        }
        Field beanField;

        if (parameterMap.containsKey(sourceName)) { // 如果target类字段和source类字段不一致
            String bFiled = parameterMap.remove(sourceName);
            beanField = target.getClass().getDeclaredField(bFiled);
            beanField.setAccessible(true);
            beanField.set(target, sourceField.get(source));
            return true;
        }
        return false;
    }


    /**
     * @param bo BO类
     * @param bean Bean 类
     * @param parameterMap key为BO类特有的属性, val为Bean类特有的属性，且BO特有属性对应的值为Bean特有属性对应的值
     * @param <T> Bean类,
     * @return 通过BO类替换成Bean类
     */
    public static <T, E> T bo2bean(E bo, Class<T> bean, Map<String, String> parameterMap){
        T b = null;

        try {
            b = copy(bo, bean, parameterMap);
        } catch (NoSuchMethodException |InvocationTargetException | InstantiationException | IllegalAccessException |NoSuchFieldException  e) {
            e.printStackTrace();
        }
        return b;
    }




    /**
     * @param bo BO类
     * @param bean Bean 类
     * @param <T> Bean类,
     * @return 通过BO类替换成Bean类
     */
    public static <T, E> T bo2bean(E bo, Class<T> bean){
        T b = null;
        try {
            b = copy(bo, bean, null);
        } catch (NoSuchMethodException |InvocationTargetException | InstantiationException | IllegalAccessException |NoSuchFieldException  e) {
            e.printStackTrace();
        }
        return b;
    }


    /**
     * @param bean Bean 类
     * @param vo VO类
     * @param parameterMap key为Bean类特有的属性, val为Vo类特有的属性，且Bean特有属性对应的值为Vo特有属性对应的值
     * @param <T> Vo类,
     * @return 通过Bean类替换成Vo类
     */
    public static <T, E> T bean2vo(E bean, Class<T> vo, Map<String, String> parameterMap){
        T v = null;
        try {
            v = copy(bean, vo, parameterMap);
        } catch (NoSuchMethodException |InvocationTargetException | InstantiationException | IllegalAccessException |NoSuchFieldException  e) {
            e.printStackTrace();
        }
        return v;
    }


    /**
     * @param bean Bean 类
     * @param vo VO类
     * @param <T> Vo类,
     * @return 通过Bean类替换成Vo类
     */
    public static <T, E> T bean2vo(E bean, Class<T> vo){
        T v = null;
        try {
            v = copy(bean, vo, null);
        } catch (NoSuchMethodException |InvocationTargetException | InstantiationException | IllegalAccessException |NoSuchFieldException  e) {
            e.printStackTrace();
        }
        return v;
    }
}
